import gdata
import gdata.alt.appengine
import gdata.spreadsheet
import gdata.spreadsheet.service


class ContextBGLabel(object):
    def __init__(self, name, weight):
        self.name = name
        self.weight = weight


def HandleContextKey(row_dict, context_dict):
    label_keys = ['bgfilter', 'bgeliminate', 'bgboost']

    ckey = row_dict['contextkey'].text
    final_val = ''

    contextvalue = row_dict.get('contextvalue')
    cval = ''
    if contextvalue and contextvalue.text:
        cval = contextvalue.text

    if ckey == 'keyword':
        # Keywords are accumulated in a single value.
        keyword_list = context_dict.setdefault('keywords', [])
        keyword_list.append(cval)

    elif ckey in label_keys:
        # Labels have two values to insert into the dict, instead of
        # one.  They also are appended to a list.
        try:
            weight = float(row_dict['contextvalue2'].txt)
        except (ValueError, KeyError):
            weight = 0.7

        label = ContextBGLabel(cval, weight)
        list_name = "%ss" % ckey  # bgfilter goes into the bgfilters list.
        label_list = context_dict.setdefault(list_name, [])
        label_list.append(label)

    else:
        # Default case, cval is a string and does not need special
        # handling.
        context_dict[ckey] = cval


def HandleAnnotation(row_dict, annos_list, default_labels):
    urlpattern = row_dict['urlpattern'].text

    try:
        score = float(row_dict['score'].text)
    except (ValueError, KeyError):
        score = default_score

    labels_obj = row_dict.get('labels')
    if labels_obj and labels_obj.text:
        labels = labels_obj.text.split(',')
    else:
        labels = default_labels[:]

    annos_list.append({
            'urlpattern': urlpattern,
            'score': score,
            'labels':labels
            })


def GetCSEPatternsFromPublicSpreadsheet(key, default_score, default_labels):
    """Fetch Google Spreadsheet, return list of annotation data.

    Fetches a public (i.e. published) Google spreadsheet with the
    given spreadsheet key.  Each row's "url pattern", "score", and
    "labels" columns' values will be stored in a dictionary, and that
    dictionary is appended to a list which is eventually returned to
    the caller.  For example,
      {'urlpattern':'foo.com/*', 'score':0.3, labels:['l1', 'l2']}
    Note that the urlpattern is a string, score is a float, and labels
    is a list of strings.

    NOTE: a column with name url_pattern or "url pattern" will show up
    as urlpattern in the data we receive in this function.

    To store multiple labels in a single spreadsheet cell, use a
    comma to separate the label names.

    To store a CSE definition ("context") in the same spreadsheet, add
    two columns called "context key" and "context value".  An inline CSE
    definition requires at least the following items:

      title
      description
      [bgfilter | bgeliminate | bgboost]

    The names above appear in the "context key" column, and the associated
    value should be in the "context value" column.

    If you wish to specify a weight for a background label, add
    another column called "context value2" and store the weight there
    (in the appropriate row, of course).  Weight values should be in
    [-1.0, 1.0].  See this page for an explanation of positive and
    negative weights.
      http://code.google.com/intl/en/apis/customsearch/docs/ranking.html#score

    Keywords are optional and can be specified one (phrase) at a time
    using as many "keyword" lines as needed.  Other optional
    context items include:
      visible (boolean, default "false")
      language (string, default "en")

    You could put the CSE definition and some annotations into the
    same spreadsheet rows, but that would indicate very bad taste
    on your part.

    Args:
      key:
        unique spreadsheet key, as shown in a Google Spreadsheet url.
        For the url
          http://spreadsheets.google.com/ccc?key=pYosaaRobOPcI4jqilT9rBA
        the key is pYosaaRobOPcI4jqilT9rBA

      default_score:
        score (float) used when the spreadsheet is missing a score, or the
        score is not numeric for this url pattern.

      default_labels:
        list of label names (strings) used when the spreadsheet is missing
        a label for this url pattern.  This list is copied into the
        output.

    Returns:
      (context, annos) where:
        annos: list of CSE annotation attribute dictionaries.  See above in
               overall description.
        context: dictionary with context items described above.
    """
    client = gdata.spreadsheet.service.SpreadsheetsService()
    gdata.alt.appengine.run_on_appengine(client)

    data_feed = client.GetListFeed(
        key, wksht_id='default', visibility='public', projection='values')

    annos = []
    context = {
        'language': 'en',
        'visible': 'False',
        }

    for feed_row in data_feed.entry:
        row_dict = feed_row.custom

        contextkey = row_dict.get('contextkey')
        if contextkey:
            HandleContextKey(row_dict, context)

        urlpattern = row_dict['urlpattern'].text
        if urlpattern:
            HandleAnnotation(row_dict, annos, default_labels)

    return (context, annos)

